package space;

import factory.ConstantsFactory;

import factory.WorldInterfaceFactory;

import interfaces.ActionInterface;
import interfaces.AgentInterface;
import interfaces.WorldInterface;
import interfaces.impl.HumanInteraction;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import constants.Constants;

import database.MAction;
import database.MAgent;
import database.MSpecialFeature;
import database.MWorld;
import database.MWorldObject;

import objects.SpetialFeature;
import objects.WorldObject;
import universe.Universe;
import util.CledaConnector;

public class Space {
	
	private ThreadUpdateDatabese thread = null;
	private ArrayList<Universe> universeLis;
	private int cont = 0;
	
	public Space(){
		universeLis= new ArrayList<Universe>();
	}

	public void update(double time) {
		
		
		for (Universe universe : universeLis){
			universe.update(time);
		}
		cont+=time;
		
		if(cont>2000){
			//updateDatabase();
		}
		
	}

	private void updateDatabase() {
		
		Session session = CledaConnector.getInstance().getSession();
	    session.beginTransaction();
		//usa
				
		
	    for(Universe universe : universeLis){

	    	List<MWorld> list = new ArrayList<MWorld>();
		    list =session.createCriteria(MWorld.class).add(Restrictions.eq("id", universe.getUniverseId())).list();
		    
		    if(list.isEmpty() || list.size()>1){
		    	continue;
		    }
		    
		    for(WorldObject obj : universe.getListObjects()){
		    	System.out.println("AAA Reference del objeto en el universe: "+obj.getObjectReference());
		    	List<MWorldObject> listObj = new ArrayList<MWorldObject>();	
		    	listObj =session.createCriteria(MWorldObject.class).add(Restrictions.eq("id", obj.getID())).list();
		    	
		    	MWorldObject objToUpdate = null;
		    	if(listObj.isEmpty() ){
		    		objToUpdate = saveObject(obj,list.get(0),session);
			    	
			    }else{
			    	objToUpdate = listObj.get(0);
			    }
		    	System.out.println("BBB Reference del objeto en el universe: "+objToUpdate.getObjectRefName());
		    	updateObjectDatabase(session, list.get(0), obj, null,objToUpdate);
		    	
		    }
		    
		    
	    }
	    session.getTransaction().commit();
	    // SE CIERRA
	    session.close();
	    
	}

	private MWorldObject updateObjectDatabase(Session session, MWorld mWorld, WorldObject obj, MWorldObject father, MWorldObject objToUpdate) {
		
		
		
		//obj.setID(mWorldObject.getId());
		
		if(obj.getObjectReference()==17 && father==null){
			System.out.println("asdsakjfjjjjjjjJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJj");
		}
		if(obj.getObjectReference()==17){
			System.out.println("asdsakjfjjjjjjjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
		}
		
		
		
		objToUpdate.setWorldReference(mWorld);
		//objToUpdate.setObjectId(obj.getID());
		objToUpdate.setObjectRefName(obj.getObjectReference());
		objToUpdate.setOwner(obj.getOwner());
		objToUpdate.setX((int)obj.getPosition().getX());
		objToUpdate.setY((int) obj.getPosition().getY());
		if(obj.isActive()){
			objToUpdate.setActive(Constants.TRUE);
			objToUpdate.setActivate(Constants.TRUE);
		}else{
			objToUpdate.setActive(Constants.FALSE);
			objToUpdate.setActivate(Constants.FALSE);
		}
		
		
		
		for(MSpecialFeature mFeature : objToUpdate.getSpecialFeatureList()){
			SpetialFeature fea = obj.getFeature(mFeature.getSpecialFeatureId());
			if (fea== null ){
				continue;
			}
			mFeature.setName(fea.getName());
			mFeature.setValue(fea.getValue());
			mFeature.setAditionalInfo(fea.getAditionalInfo());
			
		}
		
	
		for(WorldObject obj1 : obj.getListObjects()){
			List<MWorldObject> listObj1 = new ArrayList<MWorldObject>();	
	    	listObj1 =session.createCriteria(MWorldObject.class).add(Restrictions.eq("id", obj1.getID())).list();
	    	
	    	if(listObj1.isEmpty() || listObj1.size()>1){
		    	continue;
		    }
	    	if(obj1.getObjectReference()==17){
	    		System.out.println("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
	    	}
	    	
	    	
	    	
	    	updateObjectDatabase(session, mWorld, obj1, objToUpdate,listObj1.get(0));
	    	//session.update(objToUpdate);
		}
		
		if(father!=null){
			System.out.println("mis hijos son : "+objToUpdate.getObjectRefName());
			father.getObjectList().add(objToUpdate);
			objToUpdate.setObjectReference(father);
		}

		
	//	session.update(mWorldObject);
		return objToUpdate;
	}
	
	public void setUniverse(Universe universe){
		universeLis.add(universe);
	}
	
	public Universe getUniverse(int universeId) {
		
		for(Universe uni: universeLis){
			if(universeId == uni.getUniverseId()){
				return uni;
			}
		}
		return null;
		
	}

	public void loadFile(InputStream is) {
		
		InputStreamReader isr;
		String line;
		int x,y;
		try {
			System.out.println("Cargo mundo");
			isr = new InputStreamReader(is);
			BufferedReader input = new BufferedReader(isr);
			
			int universeId;
			int width;
			int height;
			WorldInterface worldI;
			
			
			line=input.readLine();
			String [] linesElements =  line.split(",");
			universeId=Integer.parseInt(linesElements[0]);			
			width=Integer.parseInt(linesElements[1]);
			height=Integer.parseInt(linesElements[2]);
			worldI = WorldInterfaceFactory.createNewWorldInterface(ConstantsFactory.WORLD_FIRST, width, height);
			
			Universe universe = new Universe(width, height);
			universe.setUniverseId(universeId);
			universe.setWorldI(worldI);
			universe.setSpace(this);
			
			WorldObject object= new WorldObject();
		    
			
			while((line=input.readLine())!=null){
				String comment = line.substring(0, 2);
				System.out.println("Soy la linea "+comment);
				if(comment.equals("//")){
					continue;
				}
				
				linesElements = line.split(",");
				
				
				if(Integer.parseInt(linesElements[0])==universeId){
					System.out.println("Cargo objeto de mundo "+universeId);
					object = object.load(linesElements, 1);
					
					universe.addLoadObject(object);
					for(WorldObject obj : object.getListObjects()){
						if(obj.isActive()){
							universe.addLoadObject(obj);
						}
					}
				}
				else{
					universeLis.add(universe);
					
					universeId=Integer.parseInt(linesElements[0]);			
					width=Integer.parseInt(linesElements[1]);
					height=Integer.parseInt(linesElements[2]);
					worldI = WorldInterfaceFactory.createNewWorldInterface(ConstantsFactory.WORLD_FIRST, width, height);
					
					universe = new Universe(width, height);
					universe.setUniverseId(universeId);
					universe.setWorldI(worldI);
					universe.setSpace(this);
					
				}
				
			}
			universeLis.add(universe);
			
			
		    
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		beginThread();
	}

	public ArrayList<Universe> getUniverseList() {
		
		return universeLis;
	}

	public Universe connect(int idCliente) {
		for(Universe universe : universeLis){
			if(universe.connect(idCliente)){
				return universe;
			}
		}
		return null;
	}

	public void loadDatabase() {
		
		Session session = CledaConnector.getInstance().getSession();
	    session.beginTransaction();
		//usa
		List<MWorld> list = new ArrayList<MWorld>();
	    list =session.createCriteria(MWorld.class).list();
	    

	    
	    Universe universe = new Universe(100, 100);  //TODO
	    	 
	    int id=1;
	    for(MWorld world : list){
	    	universe = new Universe(100, 100);
	    	
	    	WorldInterface worldI = WorldInterfaceFactory.createNewWorldInterface(ConstantsFactory.WORLD_FIRST, 100, 100);

			universe.setUniverseId(id);
			universe.setWorldI(worldI);
			universe.setSpace(this);
	    	id++;
	    	
	    	
	    	this.loadObjectsFromDatabase(world.getObjectList(), universe);
	    	
	    	
	    	this.setUniverse(universe);
	    }
	    
	    //session.getTransaction().commit();
	    // SE CIERRA
	    session.close();
	    beginThread();
		
	}
	
	private void beginThread() {
		
		thread = new ThreadUpdateDatabese();
		Thread hilo = new Thread(thread);
		hilo.start();
		
	}

	private void loadObjectsFromDatabase(List<MWorldObject> list, Universe universe) {
		
		
			
		for(MWorldObject obj : list){
			System.err.println("LA lista no estaba vacia, cargo los objetos");
			if(obj.isActive()==Constants.FALSE ){
				obj.setActive(Constants.FALSE);
				System.err.println("Estaba inactivo ooo "+obj.getObjectRefName());	
				continue;
			}
			
			WorldObject object= new WorldObject();
    		object.setID(obj.getId());
    		object.setObjectReference(obj.getObjectRefName());
    		object.setOwner(obj.getOwner());
    		object.getPosition().setX(obj.getX());
    		object.getPosition().setY(obj.getY());
    		
    		object.setActive(true);
    			
    		
    		
    		//object = ObjectFactory.createWorldObject(object.getObjectReference(),object.getOwner(),object.getPosition().getX(),object.getPosition().getY(),Constants.NO_ASSIGN_SPECIAL_FEATURE);
    		//object.setID(obj.getId());
    		
    		for(MSpecialFeature mFeature : obj.getSpecialFeatureList()){
    			SpetialFeature feature = new SpetialFeature();
    			
    			feature.setId(mFeature.getSpecialFeatureId());
    			feature.setName(mFeature.getName());
    			feature.setValue(mFeature.getValue());
    			feature.setAditionalInfo(mFeature.getAditionalInfo());
    			object.addSpetialFeature(feature);
    		}
    	
    		assignInactiveObjectsToFather(obj.getObjectList(), universe, object);
    		if(object.isActive()){
    			universe.addLoadObject(object);
    		}
    		//System.out.println("size del universe "+universe.getListObjects().size());
    		
		}
		
	}
	private void assignInactiveObjectsToFather(List<MWorldObject> list, Universe universe, WorldObject father) {
		
		WorldObject object = new WorldObject();
			
		for(MWorldObject obj : list){
			System.out.println("LA lista no estaba vacia, cargo los objetos 000 "+obj.getObjectRefName()+"owner: "+father.getOwner());
			
			
			object= new WorldObject();
    		object.setID(obj.getId());
    		object.setObjectReference(obj.getObjectRefName());
    		object.setOwner(obj.getOwner());
    		object.getPosition().setX(obj.getX());
    		object.getPosition().setY(obj.getY());
    		
    		
//    		if(obj.isActive()==Constants.TRUE){
//    			object.setActive(true);
//    			System.out.println("ACTIVO OBJETO");
//    		}else{
//    			object.setActive(false);
//    			System.out.println("NO ACTIVO OBJETO");
//    		}
    		object.setActive(false);
    		//double x = object.getPosition().getX();
			//double y = object.getPosition().getY();
    		//object = ObjectFactory.createWorldObject(object.getObjectReference(),object.getOwner(),object.getPosition().getX(),object.getPosition().getY(),Constants.NO_ASSIGN_SPECIAL_FEATURE);
    		//double xMid =object.getImageObject().getImageToShow().getWidth()/2;
			//double yMid =object.getImageObject().getImageToShow().getHeight()/2;
					
			//object.getImageObject().setPosition(new Position(x-xMid,y-yMid));
			//object.setPosition(new Position(x,y));
    		
    		for(MSpecialFeature mFeature : obj.getSpecialFeatureList()){
    			SpetialFeature feature = new SpetialFeature();
    			
    			feature.setId(mFeature.getSpecialFeatureId());
    			feature.setName(mFeature.getName());
    			feature.setValue(mFeature.getValue());
    			feature.setAditionalInfo(mFeature.getAditionalInfo());
    			object.addSpetialFeature(feature);
    			
    		}
    		object.setActive(false);
    		
    		father.addObject(object);
		}
		
		
	}
	
	public MWorldObject saveObject(WorldObject objectToCreate,MWorld mWorld,Session session) {
	    
	    MWorldObject obj = createObjectDatabase(session, mWorld, objectToCreate, null);
	    
	    return obj;
	}

	public MWorldObject createObjectDatabase(Session session, MWorld mWorld, WorldObject obj, MWorldObject father) {
		MWorldObject mWorldObject = new MWorldObject();
		mWorldObject.setWorldReference(mWorld);
		
		
		//obj.setID(mWorldObject.getId());
		
		mWorldObject.setObjectReference(father);
		if(father!=null){
			
			father.getObjectList().add(mWorldObject);
		}
		
		//obj.setID(mWorldObject.getId());
		//mWorldObject.setObjectId(obj.getID());
		
		mWorldObject.setObjectRefName(obj.getObjectReference());
		mWorldObject.setOwner(obj.getOwner());
		mWorldObject.setX((int)obj.getPosition().getX());
		mWorldObject.setY((int) obj.getPosition().getY());
		if(obj.isActive()){
			mWorldObject.setActive(Constants.TRUE);
		}else{
			mWorldObject.setActive(Constants.FALSE);
		}
		
		MAction mAction = new MAction();
		
		for (ActionInterface action : obj.getListActions()){
			
			mAction = new MAction();
			mAction.setObjectReference(mWorldObject);
			mAction.setActionId(action.getId());
			mAction.setName(action.getName());
			
			mWorldObject.getActionList().add(mAction);
			session.save(mAction);
			
		}
		
		MAgent mAgent = new MAgent();
		
		for (AgentInterface agent : obj.getListAgents()){
			
			mAgent = new MAgent();
			mAgent.setObjectReference(mWorldObject);
			mAgent.setAgentId(agent.getID());
			mAction.setName(agent.getName());
			
			mWorldObject.getAgentList().add(mAgent);
			session.save(mAgent);
			
		}
		for (HumanInteraction agent : obj.getListHumanInteractions()){
			
			mAgent = new MAgent();
			mAgent.setObjectReference(mWorldObject);
			mAgent.setAgentId(agent.getID());
			mAction.setName(agent.getName());
			
			mWorldObject.getAgentList().add(mAgent);
			session.save(mAgent);
			
		}
		
		MSpecialFeature mSpecialFeature= new MSpecialFeature();
		
		for (SpetialFeature feature : obj.getListFeatures()){
			
			mSpecialFeature= new MSpecialFeature();
			mSpecialFeature.setObjectReference(mWorldObject);
			
			mSpecialFeature.setSpecialFeatureId(feature.getId());
			mSpecialFeature.setName(feature.getName());
			mSpecialFeature.setValue(feature.getValue());
			mSpecialFeature.setAditionalInfo(feature.getAditionalInfo());
			
			
			mWorldObject.getSpecialFeatureList().add(mSpecialFeature);
			session.save(mSpecialFeature);
			
		}
		
		
//		for(WorldObject obj1 : obj.getListObjects()){
//			obj1.setActive(false);
//			createObjectDatabase(session, mWorld, obj1, mWorldObject);
//		}

		mWorldObject.setWorldReference(mWorld);
	    mWorld.getObjectList().add(mWorldObject);
	    int id = (Integer)session.save(mWorldObject);
	    obj.setID(id);
		
		return mWorldObject;
	}


	public class ThreadUpdateDatabese implements Runnable{
		int time = 0;

		@Override
		public void run() {
			while(true){
				try {
					System.out.println("UPDATE BASE DE DATOS");
					Thread.sleep(2500);
					System.out.println("UPDATE BASE DE DATOS1");
					updateDatabase();
					System.out.println("UPDATE BASE DE DATOS1");
					
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
			
		}
		
		
	}

}
